(ns game
  (:require [utils :refer :all])
  (:gen-class))

;; The map is represented by a 2D vector of Sites
(defrecord Site [^int x ^int y ^int production ^int strength ^int owner])

(def frontier (atom nil))
(def board-rows (atom nil))
(def board-cols (atom nil))
(def board-half (atom nil))


(def directions [:still :north :east :south :west])
(def cardinal-directions (rest directions))

(defn site-with-offset [game-map {:keys [x y]} [x-offset y-offset]]
  (let [new-x (mod (+ x x-offset) @board-cols)
        new-y (mod (+ y y-offset) @board-rows)]
    (get-in game-map [new-y new-x])))

(defn adjacent-site [game-map site direction]
  (let [width @board-cols
        height @board-rows
        new-x (condp = direction
                :west (mod (dec (:x site)) width)
                :east (mod (inc (:x site)) width)
                (:x site))
        new-y (condp = direction
                :north (mod (dec (:y site)) height)
                :south (mod (inc (:y site)) height)
                (:y site))]
    (get-in game-map [new-y new-x])))

(def overkill-offsets
  {:west [[-1 0] [-2 0] [-1 1] [-1 -1]]
   :east [[1 0] [2 0] [1 -1] [1 1]]
   :south [[0 1] [0 2] [-1 1] [1 1]]
   :north [[0 -1] [0 -2] [-1 -1] [1 -1]]})

(defn kill? [game-map {:keys [owner strength] :as site} [direction offsets]]
  (let [[head & tails] (map (partial site-with-offset game-map site) offsets)]
    (log "mysite:" site "head:" head "tails:" tails)
    (when
        (or
         ;; kill
         (and (not= owner (:owner head))
              (> strength (:strength head)))
         (and (not (#{owner 0} (:owner head)))
              (> (count (filter #(= (:owner head) (:owner %)) tails)) 1)))
      direction)))

(defn overkill-direction [game-map site]
  (some (partial kill? game-map site) overkill-offsets))

(defn single-dimension-distance
  "Computes the distance between two integers mod m"
  ^long [^long p1 ^long p2 ^long m]
  (let [dist (unchecked-subtract p1 p2)
        unwrapped-distance (if (pos? dist) dist (unchecked-negate dist))]
    (min unwrapped-distance (unchecked-subtract m unwrapped-distance))))

(defn distance ^long [site1 site2]
  (unchecked-add (single-dimension-distance (:x site1) (:x site2) @board-cols)
                 (single-dimension-distance (:y site1) (:y site2) @board-rows)))
